home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / Source / MacStarter (THINK C 5.0⁄6.0) / other applicationProcs files / pentominos.c < prev    next >
Text File  |  1992-10-11  |  22KB  |  550 lines

  1. /* This file demonstrates how ApplicationIdle can be used to drive,
  2.    a complicated computation in an application written from MacStarter. 
  3.    To use this file, you should add it to the MacStarter.π project
  4.    and delete the current applicationProcs file.
  5.        The problem in this case is the solution of "pentomino puzzles."
  6.    A pentomino is a tile consisting of 5 connected squares.  There are
  7.    exactly 12 different possilbe pentominos.  The puzzles involve
  8.    placing one of each type of pentomino on an 8-by-8 board.  This will
  9.    leave four blank spaces.  In this program, the spaces that are to
  10.    be left blank are specified in advance.  The basic algorithm used
  11.    is a simple recursive depth-first search:  Try to place a piece at
  12.    the first empty square; if it fits, go on to the next empty space
  13.    and repeat; if the puzzle isn't solved fails, try the next piece;
  14.    if there is no other piece to try, then there is no solution.
  15.    Unfortunately, I can't really use a single recursive function
  16.    because I am insisting that each call to ApplicationIdle only
  17.    do a part of the problem.  There is also an interesting problem 
  18.    of data representation, which is commented on below even though it
  19.    has nothing to do with MacStarter.
  20.        This program can be set to continue running in the background
  21.    under system 7 or multifinder.  Before building the application,
  22.    go to the Set Project Type command in the Project menu.  There is
  23.    a small icon labeled "SIZE flags".  This will turn into a pop-up
  24.    menu if you click on it.  Simply choose the command "Background
  25.    Null Events" from this menu.  Then, ApplicationIdle will continue
  26.    to be called even when the application is in the background.
  27.        All places where this file has been modified (from the 
  28.    original applicationProcs.c) are commented with comments
  29.    that begin with //
  30. */
  31.  
  32.  
  33. #include "globals-MacStarter.h"
  34.  
  35. long gEventWaitTime = 0;  // Changed from 100000 to 0 so that the
  36.                           // function ApplicationIdle will be called
  37.                           // as often as possible.
  38.  
  39. MenuHandle editMenu, fileMenu;
  40.  
  41. void InitApplication(void);
  42. void UpdateMenus(void);
  43. void DoEditMenu(int itemNum);
  44. void DoFileMenu(int itemNum, int* done);
  45. void DoOtherMenu(int menuID, int itemNum);
  46. void ApplicationIdle(void);
  47. void CleanUpApplication(void);
  48. void AboutBox(void);
  49. void DoNewCommand(void);
  50.  
  51. const short squareSize = 21;  // This is the size of each square in the
  52.                               // 8-by-8 playing board.  It can be
  53.                               // adjusted slightly to make larger or
  54.                               // smaller boards.
  55.  
  56. short WindowCt = 0;  // This variable will count the number of windows
  57.                      // that have been opened so far.  It is incremented
  58.                      // in DoNewCommand and is used in OpenInRect to
  59.                      // position the window.
  60.  
  61. typedef short boardData[100];  // The 8-by-8 board is actually
  62.                                // represented by a 10-by-10 data structure
  63.                                // in which the cells along the border
  64.                                // are declared permanently "filled"
  65.                                // This simplifies testing whether a given
  66.                                // piece fits at a given position on the 
  67.                                // board.  Furthermore, this 10-by-10 board
  68.                                // is represented by a 1-dimensional array
  69.                                // in which the 10*i+j-th entry represents
  70.                                // row j and column i on the board.
  71.  
  72. const pieces[63][5] = {
  73.    { 1, 1,2,3,4 },         // This array represents everything the program
  74.    { 1, 10,20,30,40 },     // knows about the individual pentominos.  Each
  75.    { 2, 9,10,11,20 },      // row in the array represents a particular
  76.    { 3, 1,10,19,20 },      // pentomino in a particular orientation.  Different
  77.    { 3, 10,11,12,22 },     // orientations are obtained by rotating or flipping
  78.    { 3, 1,11,21,22 },      // the pentomino over.  Note that the program must
  79.    { 3, 8,9,10,18 },       // try each pentomino in each possible orientation,
  80.    { 4, 10,20,21,22 },     // but must be careful not to reuse a piece if
  81.    { 4, 1,2,10,20 },       // it has already been used on the board in a
  82.    { 4, 10,18,19,20 },     // different orientation.
  83.    { 4, 1,2,12,22 },       //     The pentominoes are numbered from 1 to 12.
  84.    { 5, 1,2,11,21 },       // The first number on each row tells which pentomino
  85.    { 5, 8,9,10,20 },       // that row represents.  Note that there can be
  86.    { 5, 10,19,20,21 },     // up to 8 different rows for each pentomino.
  87.    { 5, 10,11,12,20 },     // some pentominos have fewer rows because they are
  88.    { 6, 10,11,21,22 },     // symmetric.  For example, the pentomino that looks
  89.    { 6, 9,10,18,19 },      // like:
  90.    { 6, 1,11,12,22 },      //           GGG
  91.    { 6, 1,9,10,19 },       //           G G
  92.    { 7, 1,2,10,12 },       //
  93.    { 7, 1,11,20,21 },      // can be rotated into three additional positions,
  94.    { 7, 2,10,11,12 },      // but flipping it over will give nothing new.
  95.    { 7, 1,10,20,21 },      // So, it has only 4 entries in the array.
  96.    { 8, 10,11,12,13 },     //     The four remaining entries in the array
  97.    { 8, 10,20,29,30 },     // describe the given piece in the given orientation,
  98.    { 8, 1,2,3,13 },        // in a way convenient for placing the piece into
  99.    { 8, 1,10,20,30 },      // the one-dimensional array that represents the
  100.    { 8, 1,11,21,31 },      // board.  As an example, consider the row
  101.    { 8, 1,2,3,10 },        //
  102.    { 8, 10,20,30,31 },     //           { 7, 1,2,10,19 }
  103.    { 8, 7,8,9,10 },        //
  104.    { 9, 1,8,9,10 },        // If this piece is placed on the board so that
  105.    { 9, 10,11,21,31 },     // its topmost/leftmost square fills position
  106.    { 9, 1,2,9,10 },        // p in the array, then the other four squares
  107.    { 9, 10,20,21,31 },     // will be at positions  p+1, p+2, p+10, and p+19.
  108.    { 9, 1,11,12,13 },      // To see whether the piece can be played at that
  109.    { 9, 10,19,20,29 },     // position, it suffices to check whether any of
  110.    { 9, 1,2,12,13 },       // these five squares are filled.  If the piece is
  111.    { 9, 9,10,19,29 },      // played, those five places in the array are filled
  112.    { 10, 8,9,10,11 },      // with a letter representing the pentomino ('A' for
  113.    { 10, 9,10,20,30 },     // pentomino 1, 'B' for pentomino 2, etc.)
  114.    { 10, 1,2,3,11 },
  115.    { 10, 10,20,21,30 },
  116.    { 10, 1,2,3,12 },
  117.    { 10, 10,11,20,30 },
  118.    { 10, 9,10,11,12 },
  119.    { 10, 10,19,20,30 },
  120.    { 11, 9,10,11,21 },
  121.    { 11, 1,9,10,20 },
  122.    { 11, 10,11,12,21 },
  123.    { 11, 10,11,19,20 },
  124.    { 11, 8,9,10,19},
  125.    { 11, 1,11,12,21 },
  126.    { 11, 9,10,11,19 },
  127.    { 11, 9,10,20,21 },
  128.    { 12, 1,10,11,21 },
  129.    { 12, 1,2,10,11 },
  130.    { 12, 10,11,20,21 },
  131.    { 12, 1,9,10,11 },
  132.    { 12, 1,10,11,12 },
  133.    { 12, 9,10,19,20 },
  134.    { 12, 1,2,11,12 },
  135.    { 12, 1,10,11,20 }, 
  136.  };
  137.  
  138. typedef enum {   // This type is a convenienct for keeping track a board's status.
  139.    settingUp,  // = The user has not yet chosen the four empty spaces.
  140.    running,    // = The program is looking for a solution.
  141.    finished,   // = A solution has been found and is being displayed
  142.    noSolution  // = After trying all possibilities, no solution has been found
  143. } winState;
  144.  
  145.  
  146. // Declare two functions for placing pieces and removing pieces from the
  147. // board.  Note that these functions are responsible for maintaining both
  148. // the screen and the board data structure.  (It is not a good idea to
  149. // separate such functions.)  These are both called by the higher level
  150. // function myWindow::playPiece.
  151.  
  152. short putPiece(short piece, short where, boardData board);   
  153. short erasePiece(short piece, short where, boardData board); 
  154.  
  155. // Function putPiece tries to place a specifed piece in a specified position
  156. // on the board boardData.  If all the locations needed by the piece are
  157. // empty, then this function fills in those spaces in the array with the
  158. // number of the pentomino and also draws the piece on the board.
  159. // In this case, a value of 1 is returned.  If the piece cannot be played,
  160. // a value of 0 is returned.  This function assumes that the drawing port is
  161. // set to the correct window.  Note that the parameter pieceNum is an index
  162. // to the data for the piece in the global array "pieces"; the actual number of
  163. // the pentomino being played is thus pieces[pieceNum][0].
  164.  
  165. short putPiece(short pieceNum, short where, boardData board){
  166.    short i,j,k,loc;
  167.    // test if any of the spaces are already filled
  168.    if (board[where])
  169.       return 0;
  170.    for (i=1; i<5; i++)
  171.       if (board[ where + pieces[pieceNum][i] ])
  172.          return 0;
  173.    // if the piece can be played, then do so.
  174.    board[where] = pieces[pieceNum][0] - 1 + 'A';
  175.    k = where % 10;
  176.    j = where / 10;
  177.    MoveTo((k-1)*squareSize+8,(j-1)*squareSize+14);
  178.    DrawChar(board[where]);
  179.    for (i=1; i<5; i++) {
  180.       loc = where + pieces[pieceNum][i];
  181.       board[loc] = pieces[pieceNum][0]-1+'A';
  182.       k = loc % 10;
  183.       j = loc / 10;
  184.       MoveTo((k-1)*squareSize+8,(j-1)*squareSize+14);
  185.       DrawChar(board[loc]);
  186.       if (board[loc] == '@') {
  187.          k++;
  188.       }
  189.     }
  190.     return 1;
  191. }
  192.  
  193.  
  194. // Function erasePiece is called to remove a piece from the board
  195. // and from the screen.  It is assumed that the drawing port is set
  196. // to the appropriate window when the function is called.
  197. // It is also assumed that the specified piece is actually at the
  198. // specified location!!
  199.  
  200. short erasePiece(short pieceNum, short where, boardData board){
  201.    short i,j,k,loc;
  202.    k = where % 10;
  203.    j = where / 10;
  204.    MoveTo((k-1)*squareSize+8,(j-1)*squareSize+14);
  205.    DrawChar(board[where]);
  206.    board[where] = 0;
  207.    for (i=1; i<5; i++) {
  208.       loc = where + pieces[pieceNum][i];
  209.       k = loc % 10;
  210.       j = loc / 10;
  211.       MoveTo((k-1)*squareSize+8,(j-1)*squareSize+14);
  212.       DrawChar(board[loc]);
  213.       board[loc] = 0;
  214.     };
  215.    return 1;
  216. }
  217.  
  218.  
  219.  
  220.  
  221. class myWindow : public xWindow {
  222.  
  223.    // Data needed for this window; each window represents one puzzle board
  224.    
  225.    winState state;       // window state; type winState is defined above
  226.    boardData filled;     // data for the puzzle board associated with this window
  227.    short clicked;        // how many squares has the user clicked on?  These are
  228.                          //   the squares that are to remain empty.  When the 
  229.                          //   user has clicked on four such squares, the program
  230.                          //   starts solving the puzzle.
  231.    short played;         // how many pieces are currently played on the board?
  232.    short used[13];       // used[p] is set to 1 if pentomino number p is currently
  233.                          //   on the board (used[0] is not used)
  234.    short pieceStack[12]; // pieceStack[0],...,pieceStack[played-1] give the
  235.                          //   list of pieces currently on the board.  Each entry
  236.                          //   is actually an index to the global array "pieces".
  237.                          //   It is possible that pieces[played-1] is -1,
  238.                          //   indicating that no piece has yet been tried on
  239.                          //   the current top "level of recursion".
  240.    short squareStack[13];// squareStack[0],...,squareStact[played-1] record the
  241.                          //   next empty square on the board after each
  242.                          //   of the pieces in pieceStack was played
  243.  
  244.  public:
  245.    void playPiece(void); // this is a new function, responsible for placing
  246.                          // the next piece on the board.
  247.                          
  248.    virtual void OpenInRect(Str255 title, int left, int top, int right, int bottom);   
  249.    virtual short Close(void);
  250.  
  251.  protected:
  252.    virtual void SetDefaults(void);
  253.    virtual void doKey(char ch);
  254.    virtual void doContentClick(Point localPt);
  255.    virtual void adjustToNewSize(void);
  256.    virtual void doRedraw(Rect* badRect);
  257.    virtual void doHScroll(int dh);
  258.    virtual void doVScroll(int dv);
  259.    virtual void doActivate(int active);
  260. };
  261.  
  262.  
  263.  
  264. // Function playPiece is called by function ApplicationIdle to place the
  265. // next piece on the board.  It does just one step in solving the puzzle.
  266. // Actually, this function is called only for the first window in the
  267. // list of windows, xWindowList, which contains all the windows currently
  268. // open in the program.  (xWindowList is a global variable.)  The function
  269. // call is passed down this list by the first statement of this function,
  270. // so that each window gets a chance to do one step in its puzzle.
  271. // (This is the heart of the algorithm that solves the pentominos puzzle.
  272. //  It imitates a recursive, depth-first search.)
  273.  
  274. void myWindow::playPiece(void) {
  275.    short pieceNum;
  276.    short emptySquare;
  277.    if (nextWindow)  // pass function call down chain of open windows.
  278.       ((myWindow*)nextWindow)->playPiece();
  279.    if (state != running)  // this function doesn't do anything
  280.       return;             //   in a window that isn't currently "running"
  281.    SetPort(theWindow);
  282.    do { // Imagine here that you are on one level of the recursion,
  283.         // and you have just returned from trying all the possibilities
  284.         // at other levels.  You want to try the next possible piece
  285.         // on this level.  That is what is done by this body of this
  286.         // do loop, except that it also handles the two extreme cases:
  287.         // when you first get to this level (indicated by a value of -1
  288.         // in pieceStack[played]) and when there are no other pieces to
  289.         // play (indicated when pieceNum becomes 63, which causes you
  290.         // to back up one level and repeat the do loop on that level);
  291.         // If you back up all the way to the top level, then you know
  292.         // there are no solutions).
  293.      emptySquare = squareStack[played];
  294.      if (pieceStack[played] > -1) {  // remove previous piece tried, if any
  295.           ForeColor(whiteColor);
  296.           erasePiece(pieceStack[played],squareStack[played],filled);
  297.           ForeColor(blackColor);
  298.           used[pieces[pieceStack[played]][0]] = 0;
  299.      };
  300.      for (pieceNum = pieceStack[played]+1; 
  301.           pieceNum < 63 && 
  302.             (used[pieces[pieceNum][0]] || !putPiece(pieceNum,emptySquare,filled));
  303.           pieceNum ++);  // increment pieceNum until you get to a piece
  304.                          // that fits, or run out of pieces
  305.      if (pieceNum >= 63) {  // if you ran out of pieces, back up a level
  306.         played--;
  307.         if (played == -1) {
  308.            state = noSolution;
  309.            SetTitle("\pNo Solution");
  310.            SysBeep(2);
  311.            return;
  312.         }
  313.      }
  314.    } while (pieceNum >= 63);  // repeat if didn't play a piece on this level
  315.    pieceStack[played] = pieceNum;  // record the piece that was played
  316.    used[pieces[pieceNum][0]] = 1;
  317.    if (played == 11) {  // a solution was found
  318.       SysBeep(1);
  319.       SysBeep(1);
  320.       SysBeep(1);
  321.       SetTitle("\pClick for More");
  322.       state = finished;
  323.    }
  324.    else {  // This really sets up a simulated call to the recursive
  325.            // algorithm on the next level down
  326.       played++;  // advance to next level
  327.       pieceStack[played] = -1;  // on the new level, no piece has been tried
  328.       while (filled[emptySquare])
  329.          emptySquare++;  // find out which is the next square to be filled
  330.       squareStack[played] = emptySquare;
  331.    }
  332. }
  333.  
  334. void myWindow::SetDefaults(void) {
  335.    short i,j;
  336.    inherited::SetDefaults();
  337.    features = hasGoAway;  // The window is fixed-size with no scroll bars.
  338.    clicked = 0;         // Initialize window data...
  339.    state = settingUp; 
  340.    squareStack[0] = 11;  // first square on board (not counting border)
  341.    played = 0;           // no pieces played
  342.    pieceStack[0] = -1;   // indicates that no pieces have been tried yet either
  343.    for (i=0; i<100; i++) // fill in the border with -1's
  344.      filled[i] = -1;
  345.    for (i=1; i<9; i++)   // fill in the rest of the board with empty spaces (0's)
  346.      for (j=1; j<9; j++)
  347.         filled[j*10+i] = 0;
  348.    for (i=1;i<13;i++)   // for each pentomino, record that it has not been used
  349.       used[i] = 0;
  350. }
  351.  
  352.  
  353. // Function OpenInRect has been modified to ignore the parameters that give
  354. // the window position and to use a formula of my own to set up the
  355. // window location.  The windows are all the same size and each successive
  356. // windows is offset from the previous window.  WindowCt is a global
  357. // variable that tells how many windows have been opened so far.
  358.  
  359. void myWindow::OpenInRect(Str255 title, int left, int top, int right, int bottom) {
  360.    inherited::OpenInRect(title,
  361.                          40+10*(WindowCt%25),
  362.                          55+10*(WindowCt%10),
  363.                          40+8*squareSize-1+10*(WindowCt%25),
  364.                          55+8*squareSize-1+10*(WindowCt%10));
  365. }
  366.  
  367. short myWindow::Close(void) {
  368.    inherited::Close();
  369. }
  370.  
  371.  
  372. // Here is a feature that is undocumented elsewhere:  If the user hits any
  373. // key before clicking on four squares, the program will start solving the
  374. // puzzle; there will be some extra empty squares on the board after all 12
  375. // pentominos have been placed.
  376.  
  377. void myWindow::doKey(char ch) {
  378.    if (state >= running)
  379.       return;
  380.    state = running;
  381.    while (filled[squareStack[0]])
  382.        squareStack[0]++;
  383.    SetTitle("\pPentominos");
  384.    clicked = 4;
  385. }
  386.  
  387.  
  388.  
  389. void myWindow::doContentClick(Point localPt) {
  390.    short i,j;
  391.    Rect R;
  392.    if (state == finished) {    // After a solution has been found, the user
  393.       state = running;         // can restart the search for another solution
  394.       SetTitle("\pPentominos");// by clicking on the window. (Note that the
  395.       return;                  // title of the window depends on the current state.)
  396.    };
  397.    if (state == settingUp) {   // find which square the user clicked on, and
  398.                                // toggle its state (full to empty to empty to full)
  399.       j = localPt.h / squareSize + 1;
  400.       i = localPt.v / squareSize + 1;
  401.       SetRect(&R,(j-1)*squareSize,(i-1)*squareSize,j*squareSize-1,i*squareSize-1);
  402.       InvertRect(&R);
  403.       filled[i*10+j] = 1 - filled[i*10+j];
  404.       if (filled[i*10+j])
  405.          clicked++;
  406.       else
  407.          clicked--;
  408.       if (clicked == 4) {   // The fourth space has just been specified; start running
  409.          SetTitle("\pPentominos");
  410.          state = running;
  411.          while (filled[squareStack[0]])
  412.             squareStack[0]++;  // (squareStack[0] is supposed to be the first
  413.                                //  available square; the user might have eliminated
  414.                                //  one or more squares at the beginning of the
  415.                                //  board.)
  416.       }
  417.    }
  418. }
  419.  
  420.  
  421.  
  422. // Function doRedraw simply redraws the board as it currently exists.
  423.  
  424. void myWindow::doRedraw(Rect* badRect){
  425.    Rect R;
  426.    short i,j;
  427.    for (i=1;i<8;i++) {   // draw vertical lines
  428.       MoveTo(i*squareSize-1,0);
  429.       Line(0,8*squareSize);
  430.    };
  431.    for (j=1;j<8;j++) {   // draw horizontal lines
  432.       MoveTo(0,j*squareSize-1);
  433.       Line(8*squareSize,0);
  434.    };
  435.    for (i=1;i<9;i++)
  436.       for (j=1;j<9;j++) {   // fill in squares as appropriate
  437.          if (filled[j*10+i] == 1) {
  438.             SetRect(&R,(i-1)*squareSize,(j-1)*squareSize,i*squareSize-1,j*squareSize-1);
  439.             PaintRect(&R);
  440.          }
  441.          else if (filled[j*10+i]) {
  442.             MoveTo((i-1)*squareSize+8,(j-1)*squareSize+14);
  443.             DrawChar(filled[j*10+i]);
  444.          }
  445.       }
  446. }
  447.  
  448. void myWindow::adjustToNewSize(void) {
  449.    inherited::adjustToNewSize();
  450. }
  451.  
  452. void myWindow::doHScroll(int dh) {
  453.    inherited::doHScroll(dh);
  454. }
  455.  
  456. void myWindow::doVScroll(int dv) {
  457.    inherited::doVScroll(dv);
  458. }
  459.  
  460. void myWindow::doActivate(int active) {
  461.    inherited::doActivate(active);
  462. }
  463.  
  464.  
  465.  
  466. void InitApplication(void) {
  467.   MenuHandle appleMenu;
  468.   fileMenu = GetMHandle(2);
  469.   editMenu = GetMHandle(3);
  470.   appleMenu = GetMHandle(1);
  471.   SetItem(appleMenu,1,"\pAbout Pentominos...");  // Set the program name
  472.                                                  // for first line of Apple menu
  473.   DoNewCommand();
  474. }
  475.  
  476. void UpdateMenus(void) {
  477.    short i;
  478.    WindowPtr win;
  479.    xWindow *xwin;
  480.    win = FrontWindow();
  481.    if ( win && ((WindowPeek)win)->windowKind < 0 ) {  
  482.       EnableItem(editMenu,1);
  483.       for (i=3; i<7; i++)
  484.          EnableItem(editMenu,i);
  485.    }
  486.    else {
  487.       DisableItem(editMenu,1);
  488.       for (i=3; i<7; i++)
  489.          DisableItem(editMenu,i);
  490.    }
  491.    if (win && xWindow::Window2XWindow(win,&xwin)) {
  492.       EnableItem(fileMenu,2);  
  493.    }
  494.    else {
  495.       DisableItem(fileMenu,2);
  496.    }
  497. }
  498.  
  499. void DoEditMenu(int itemNum) {
  500. }
  501.  
  502. void DoFileMenu(int itemNum, int* done) {
  503.    xWindow *win;
  504.    if (itemNum == 4)
  505.       *done = 1;
  506.    else if (itemNum == 1)
  507.       DoNewCommand();
  508.    else if (itemNum == 2 && xWindow::Window2XWindow(FrontWindow(),&win))
  509.       win->Close();
  510. }
  511.  
  512. void DoOtherMenu(int menuID, int itemNum) {
  513. }
  514.  
  515.  
  516. // ApplicaitonIdle sends the message playPiece to the first window on the 
  517. // list of open windows.  (That window will in turn send the message on 
  518. // down the list, so that each window will have a chance to play one
  519. // piece, each time ApplicationIdle is called.)
  520.  
  521. void ApplicationIdle(void) {
  522.    if (xWindowList)  // check if the list is empty.
  523.      ((myWindow*)xWindowList)->playPiece();
  524.    // The type cast is necessary since xWindowList is declared to be of type
  525.    // xWindow, not myWindow, and only myWindows have a function playPiece.
  526. }
  527.  
  528. void CleanUpApplication(void) {
  529. }
  530.  
  531.  
  532. // Set up information about program for the About box:
  533. void AboutBox(void) {
  534.    ParamText( "\pPentominos:  An entertainment",
  535.               "\pDavid Eck",
  536.               "\pHobart and William Smith Colleges\rGeneva, NY  14456\rE-mail: eck@hws.bitnet",
  537.               "\pThis program tries to place the 12 pentominos (tiles that can be made with 5 squares) on an 8-by-8 board.  Each tile is displayed with a different letter.");
  538.    Alert(128,0L);
  539. }
  540.  
  541.  
  542. void DoNewCommand(void) {
  543.    myWindow *pentWin;
  544.    WindowCt++;  // count the windows that have been opened/
  545.    pentWin = new myWindow;
  546.    pentWin->Open("\pClick 4 Squares");  // initial title for window tells the
  547.                                         // user what to do.
  548. }
  549.  
  550.